
#ifdef GUI_AUTO_TEST

#define _AUTO_START_ 1

#include <engine.h>

static Int32 s_nMaxKey = 0;

#if defined(_C28)

#define WIDTH   320
#define HEIGHT  480

static Int32 s_nKey[] = {
    VK_CAMERA,
    VK_VOLUME_UP,
    VK_VOLUME_DOWN,
    VK_PHONE_CALL,
    VK_HOME,
    VK_PHONE_HANG_UP
};

#elif defined(_Camellia)

#define WIDTH   240
#define HEIGHT  400

static Int32 s_nKey[] = {
    VK_CAMERA,
    VK_VOLUME_UP,
    VK_VOLUME_DOWN,
    VK_PHONE_CALL,
    VK_HOME,
    VK_PHONE_HANG_UP
};

#else

#define WIDTH       240
#define HEIGHT      320

static Int32 s_nKey[] = {
    VK_0, VK_1, VK_2, VK_3, VK_4, VK_5, VK_6, VK_7, VK_8, VK_9,
    VK_ASTERISK, VK_POUND,
    VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_SELECT,
    VK_PHONE_SELECT_LEFT, VK_PHONE_SELECT_RIGHT,
    VK_PHONE_CALL, VK_PHONE_HANG_UP,
    VK_CAMERA,
    VK_VOLUME_UP, VK_VOLUME_DOWN,
    VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK
};

#endif

enum TestType {
    TestType_Common,
    TestType_Record,
    TestType_Replay,
    TestType_RecordRandomEvent,
    TestType_ReplayRandomEvent,
    TestType_RandomReplay,
    TestType_Undefined
};

enum TestState {
    TestState_Waiting,
    TestState_Starting,
    TestState_Running,
    TestState_Stopped
};

enum Exception {
    Exception_Normal,
    Exception_Debugger,
    Exception_Deadlock,
    Exception_EventFull,
    Exception_OutOfMemory
};

#define MAX_MOUSE_MOVE 50

#define TAG_REGULAT    "AUTO-TEST:REGULAR"
#define TAG_RANDOM  "AUTO-TEST:RANDOM "

static TestType s_uTestType = TestType_RandomReplay;
static TestState s_uTestState = TestState_Stopped;
static Exception s_uException = Exception_Normal;
static GrafixObjectStack *s_pStack = NULL;
static IEvent *s_pIEvent = NULL;
static Int32 s_nEventToMenu = 0;
static Int32 s_nRandSpeed = 300;
static Int32 s_nMouseRatio = 98;
static Int32 s_nTotalTime = 0;
static Int32 s_nRandSeed = 0;
static Int32 s_nShowTime = 60;
static Int32 s_nStartTime = 60;
static Boolean s_bIsConfigExist = true;
static Boolean s_bRandomEvent = false;
static Int32 s_nSpaceTime = 60;
static Int32 s_nPicFolderCount = -1;
static WChar s_wPicFolderName[20];

//Screenshot
static Address* s_pSingleCaptureBuffer = NULL;
static Address* s_pSingleFrameBuffer = NULL;
static Int32 s_nSingleFrameIndex = 0;
static Int32 s_nSingleFrameSize = 0;
static Int32 s_nSinglePitch = 0;
static Int32 s_nSingleHeight = 0;

Boolean g_bIsDebugger = false;
Boolean g_bIsPauseRandomEvent = true;

#ifdef _win32

#define PROCESS_QUERY_INFORMATION (0x0400)
#define PROCESS_VM_READ           (0x0010)

static IActiveTimer *s_pTimerRunning = NULL;
static IActiveTimer *s_pTimerDebugger = NULL;
static IActiveTimer *s_pTimerReplay = NULL;

EXTERN_C Boolean __stdcall EnumProcesses(
    Int32 * pProcessIds,
    Int32 cb,
    Int32 * pBytesReturned
);

EXTERN_C Int32 __stdcall OpenProcess(
    Int32 dwDesiredAccess,
    Boolean bInheritlong,
    Int32 dwProcessId
);

EXTERN_C Boolean __stdcall EnumProcessModules(
    Int32 hProcess,
    Int32* lphModule,
    Int32 cb,
    Int32 * lpcbNeeded
);

EXTERN_C Int32 __stdcall GetModuleBaseNameA(
    Int32 hProcess,
    Int32 hModule,
    AChar * lpBaseName,
    Int32 nSize
);

EXTERN_C Boolean __stdcall CloseHandle(
    Int32 hObject
);

EXTERN_C Boolean __stdcall TerminateProcess(
    Int32 hProcess,
    UInt32 uExitCode
);

typedef union _LARGE_INTEGER {
    struct {
        Int32 LowPart;
        Int32 HighPart;
    };
    struct {
        Int32 LowPart;
        Int32 HighPart;
    } u;
    Int64 QuadPart;
} LARGE_INTEGER;

EXTERN_C Boolean __stdcall QueryPerformanceCounter(
    LARGE_INTEGER* lpPerformanceCount
);

typedef struct _SYSTEMTIME {
    Int16 wYear;
    Int16 wMonth;
    Int16 wDayOfWeek;
    Int16 wDay;
    Int16 wHour;
    Int16 wMinute;
    Int16 wSecond;
    Int16 wMilliseconds;
} SYSTEMTIME;

EXTERN_C Void __stdcall GetLocalTime(
    SYSTEMTIME *lpSystemTime
);

#else // _win32

#include <ckernel.h>

extern CKernel * g_pCKernel;
static DzTimer *s_pTimerRunning = NULL;

EXTERN_C void CDECL BspGetRTCTime(RTCTime *pRTCTime);

#endif // _zener

//
// BasicIO
//
#define MAX_FILE_HANDLER 64
#define EVENT_BUFFER_LENGTH 10

static Int32 s_nDevice = 0;
static const Int32 s_nDeviceMouse = 1;
static const Int32 s_nDeviceKeyboard = 2;

static SystemTime s_SystemTime;
static Int64 s_n64ThisTime;
static Int64 s_n64LastTime;
static UInt32 s_nElapsedTime;
static WaitResult s_WaitResult;
static IMutex *s_pIMutex = NULL;
static IEvent *s_pIEventMouse = NULL;
static IEvent *s_pIEventKeyboard = NULL;
static Int32 s_nFileObject[MAX_FILE_HANDLER];
static Int32 s_fhScript = -1;
static Int32 s_pEventBuffer[EVENT_BUFFER_LENGTH];
static Int32 s_nEventIndex = 0;

enum OpenMode {
    OpenMode_ReadOnly,
    OpenMode_RW
};

Int32 itowchar(Int32 FrameIndex, WChar TempStr[], Int32 index)
{
    WChar ResultStr[20];
    Int32 result = 0, i = 0, k = 0;
    Int32 Temp = FrameIndex;

    if (Temp == 0) {
        TempStr[0]= 0x30;
        TempStr[1]= 0x30;
        TempStr[2]= L'\0';
        return (2);
    }

    while (Temp != 0) {
        result = Temp % index;
        ResultStr[i++] = 0x30 + result;
        Temp = Temp / index;
    }

    if (i == 1) {
        TempStr[0] = 0x30;
        TempStr[1] = ResultStr[0];
        TempStr[2]= L'\0';
        return (2);
    }

    for (; i > 0; i--, k++) {
        TempStr[k] = ResultStr[i - 1];
    }
    TempStr[k]= L'\0';
    return (k - 1);
}

class BasicIO {

public:
    BasicIO();
    ~BasicIO();

    ECode BasicOpen(WChar *pwszFileName, OpenMode uOpenMode);

    ECode BasicRead(Byte *pBuffer, UInt32 uSize, UInt32 uCount);

    ECode BasicWrite(Byte *pBuffer, UInt32 uSize, UInt32 uCount);

    ECode BasicSeek(UInt32 uSeekPos);

    ECode BasicGetSize(UInt32 *puSize);

    ECode BasicEndOfFile();

private:
    UInt32 m_uOffset;
    UInt32 m_uSize;
    IAbsoluteIO *m_pIAbsoluteIO;
};

BasicIO::BasicIO()
{
    m_uOffset = 0;
    m_uSize = 0;
    m_pIAbsoluteIO = NULL;
}

BasicIO::~BasicIO()
{
    m_uOffset = 0;
    m_uSize = 0;

    if (m_pIAbsoluteIO) {
        m_pIAbsoluteIO->Release();
        m_pIAbsoluteIO = NULL;
    }
}

ECode BasicIO::BasicOpen(WChar *pwszFileName, OpenMode uOpenMode)
{
    ECode ec = NOERROR;

    IDiskManager *pIDiskManager = NULL;
    IBasicDirectory *pIBasicDirectory = NULL;
    IBasicFile *pIBasicFile = NULL;
    WStringBuf *pwsbFileName = NULL;
    WChar *pwszPath = NULL;

    pwszPath = (WChar *)malloc(_MAX_PATH << 1);
    if (!pwszPath) {
        kprintf("*ERROR* BasicIO::BasicOpen() malloc, Line: %d\n", __LINE__);
        goto __DoExit__;
    }

    ec = DzFindService(L"diskmgr", (PInterface *)&pIDiskManager);
    if (FAILED(ec)) {
        kprintf("*ERROR* DzFindService(L\"diskmgr\"), ec = 0x%x\n", ec);
        goto __DoExit__;
    }

    pwsbFileName = WStringBuf::Alloc(_MAX_PATH);
    if (!pwsbFileName) {
        kprintf("*ERROR* WStringBuf::Alloc()\n");
        goto __DoExit__;
    }

#ifdef _win32
    _wfullpath(pwszPath, pwszFileName, _MAX_PATH);
#else // _win32
    if (wcsstr(pwszFileName, L".bmp") != NULL) { //*.bmp
        wcscpy(pwszPath, L"D:/");
	    wcscat(pwszPath, s_wPicFolderName);
	    wcscat(pwszPath, L"/");
        wcscat(pwszPath, pwszFileName);

        ec = pIDiskManager->AcquireDirInterface(
            L"D:/", &pIBasicDirectory, pwsbFileName);
        if (FAILED(ec)) {
            kprintf("*ERROR* pIDiskManager->AcquireDirInterface(), ec = 0x%x, "
                "Line: %d\n", ec, __LINE__);
            goto __DoExit__;
        }

        ec = pIBasicDirectory->Lookup(s_wPicFolderName, &pIBasicFile);
        if (FAILED(ec)) {
            if (E_FS_NO_SUCH_FILE == ec) {
                ec = pIBasicDirectory->CreateDirectory(s_wPicFolderName, FileAccessMode_ReadWrite);
                if (FAILED(ec)) {
                    kprintf("*ERROR* pIBasicDirectory->CreateDirectory(%S), "
                        "ec = 0x%x, Line: %d\n", s_wPicFolderName, ec, __LINE__);
                    goto __DoExit__;
                }
                s_nPicFolderCount = s_nSingleFrameIndex / 50;
            }
            else {
                kprintf("*ERROR* pIBasicDirectory->Lookup(), ec = 0x%x\n", ec);
                goto __DoExit__;
            }
        }
        pIBasicDirectory->Release();
        if (pIBasicFile) {
            pIBasicFile->Release();
            pIBasicFile = NULL;
        }
    }
    else
        WFullPath(pwszPath, pwszFileName, _MAX_PATH);
#endif

    kprintf("**** OpenPath = %S ****\n", pwszPath);

    ec = pIDiskManager->AcquireDirInterface(
        pwszPath, &pIBasicDirectory, pwsbFileName);
    if (FAILED(ec)) {
        kprintf("*ERROR* pIDiskManager->AcquireDirInterface(%S), "
            "ec = 0x%x, Line: %d\n", pwszPath, ec, __LINE__);
        goto __DoExit__;
    }

    if (uOpenMode == OpenMode_ReadOnly) {
        ec = pIBasicDirectory->Lookup(*pwsbFileName, &pIBasicFile);
        if (FAILED(ec)) goto __DoExit__;
    }
    else {
        ec = pIBasicDirectory->Lookup(*pwsbFileName, &pIBasicFile);
        if (SUCCEEDED(ec) && pIBasicFile) {
#ifdef _win32
            SYSTEMTIME localTime;
            GetLocalTime(&localTime);

            WChar wszTemp[64];

            swprintf(wszTemp, L"#%04d%02d%02d%02d%02d%02d",
                localTime.wYear, localTime.wMonth, localTime.wDay,
                localTime.wHour, localTime.wMinute, localTime.wSecond);

            pwsbFileName->Append(wszTemp);
#else // _win32
            RTCTime tempTime;
            WChar TimeStr[30];

            BspGetRTCTime(&tempTime);

            itowchar(tempTime.uYear, TimeStr, 10);
            pwsbFileName->Append(TimeStr);

            itowchar(tempTime.uMonth, TimeStr, 10);
            pwsbFileName->Append(TimeStr);

            itowchar(tempTime.uDate, TimeStr, 10);
            pwsbFileName->Append(TimeStr);

            itowchar(tempTime.uHours, TimeStr, 10);
            pwsbFileName->Append(TimeStr);

            itowchar(tempTime.uMinutes, TimeStr, 10);
            pwsbFileName->Append(TimeStr);

            itowchar(tempTime.uSeconds, TimeStr, 10);
            pwsbFileName->Append(TimeStr);
#endif // _zener

            pIBasicFile->Release();
            pIBasicFile = NULL;
        }
        else {
            ec = pIBasicDirectory->CreateFile(
                *pwsbFileName, FileAccessMode_ReadWrite, true, &pIBasicFile);
            if (FAILED(ec)) {
                kprintf("*ERROR* pIBasicDirectory->CreateFile(), ec = 0x%x\n", ec);
                goto __DoExit__;
            }
        }
    }

__DoExit__:
    if (pIBasicFile) {
        m_pIAbsoluteIO = IAbsoluteIO::Probe(pIBasicFile);
        if (!m_pIAbsoluteIO) {
            kprintf("*ERROR* IAbsoluteIO::Probe()\n");
            goto __DoExit2__;
        }

        m_pIAbsoluteIO->AddRef();

        m_pIAbsoluteIO->GetSize((Int32 *)&m_uSize);

        m_uOffset = 0;

        pIBasicFile->Release();
        pIBasicFile = NULL;
    }
__DoExit2__:
    if (pIDiskManager) pIDiskManager->Release();
    if (pIBasicDirectory) pIBasicDirectory->Release();
    if (pwszPath) free(pwszPath);
    if (pwsbFileName) WStringBuf::Free(pwsbFileName);

    return ec;
}

ECode BasicIO::BasicRead(Byte *pBuffer, UInt32 uSize, UInt32 uCount)
{
    ECode ec = NOERROR;
    MemoryBuf memoryBuf(pBuffer, uSize * uCount);

    ec = m_pIAbsoluteIO->Read(m_uOffset, memoryBuf.GetCapacity(), &memoryBuf);
    if (FAILED(ec)) return ec;

    m_uOffset += memoryBuf.GetUsed();

    return ec;
}

ECode BasicIO::BasicWrite(Byte *pBuffer, UInt32 uSize, UInt32 uCount)
{
    ECode ec = NOERROR;
    Int32 nWritten = 0;
    MemoryBuf memoryBuf(pBuffer, uSize * uCount);

    ec = m_pIAbsoluteIO->Write(m_uOffset, memoryBuf, &nWritten);
    if (FAILED(ec)) return ec;

    m_uOffset += nWritten;

    return ec;
}

ECode BasicIO::BasicSeek(UInt32 uSeekPos)
{
    if (uSeekPos < 0 || uSeekPos > m_uSize) return -1;

    m_uOffset = uSeekPos;

    return NOERROR;
}

ECode BasicIO::BasicGetSize(UInt32 *puSize)
{
    if (!puSize) return -1;

    *puSize = m_uSize;

    return NOERROR;
}

ECode BasicIO::BasicEndOfFile()
{
    if (m_uOffset < m_uSize) return -1;

    return NOERROR;
}

Void InitFileHandler()
{
    Int32 nLoop = 0;
    while (nLoop < MAX_FILE_HANDLER) s_nFileObject[nLoop++] = 0;
}

Int32 AllocFileHandler()
{
    Int32 nLoop = 0;
    while (s_nFileObject[nLoop]) nLoop++;

    if (nLoop >= MAX_FILE_HANDLER) nLoop = -1;

    return nLoop;
}

Void SetFileHandler(Int32 nFileHandler, Void *pFileObject)
{
    s_nFileObject[nFileHandler] = (Int32)pFileObject;
}

Void FreeFileHandler(Int32 nFileHandler)
{
    s_nFileObject[nFileHandler] = 0;
}

Int32 Open(WChar *pwszFileName, OpenMode uOpenMode)
{
    Int32 nFileHandler = AllocFileHandler();
	if (nFileHandler < 0) {
	    kprintf("*ERROR* AllocFileHandler()\n");
	    return -1;
	}


    BasicIO *pBasicIO = new BasicIO();
	if (!pBasicIO) {
	    kprintf("*ERROR* new BasicIO()\n");
	    return -1;
	}

    ECode ec = pBasicIO->BasicOpen(pwszFileName, uOpenMode);
    if (FAILED(ec)) {
	    kprintf("*ERROR* pBasicIO->BasicOpen() %S\n", pwszFileName);
        FreeFileHandler(nFileHandler);

        if (ec == E_FS_FILE_EXISTS) return -2;

        return -1;
    }

    SetFileHandler(nFileHandler, pBasicIO);

    return nFileHandler;
}

Int32 Read(Byte *pBuffer, UInt32 uSize, UInt32 uCount, Int32 nFileHandler)
{
    if (nFileHandler < 0 || s_nFileObject[nFileHandler] == 0) return -1;

    BasicIO *pBasicIO = (BasicIO *)(s_nFileObject[nFileHandler]);
    pBasicIO->BasicRead(pBuffer, uSize, uCount);

    return 0;
}

Int32 Write(Byte *pBuffer, UInt32 uSize, UInt32 uCount, Int32 nFileHandler)
{
    if (nFileHandler < 0 || s_nFileObject[nFileHandler] == 0) return -1;

    BasicIO *pBasicIO = (BasicIO *)(s_nFileObject[nFileHandler]);
    pBasicIO->BasicWrite(pBuffer, uSize, uCount);

    return 0;
}

Int32 Seek(UInt32 uSeekPos, Int32 nFileHandler)
{
    if (nFileHandler < 0 || s_nFileObject[nFileHandler] == 0) return -1;

    BasicIO *pBasicIO = (BasicIO *)(s_nFileObject[nFileHandler]);
    pBasicIO->BasicSeek(uSeekPos);

    return 0;
}

Int32 GetSize(Int32 nFileHandler)
{
    if (nFileHandler < 0 || s_nFileObject[nFileHandler] == 0) return -1;

    UInt32 uSize = 0;
    BasicIO *pBasicIO = (BasicIO *)(s_nFileObject[nFileHandler]);
    pBasicIO->BasicGetSize(&uSize);

    return (Int32)uSize;
}

Int32 EndOfFile(Int32 nFileHandler)
{
    if (nFileHandler < 0 || s_nFileObject[nFileHandler] == 0) return -1;

    BasicIO *pBasicIO = (BasicIO *)(s_nFileObject[nFileHandler]);
    ECode ec = pBasicIO->BasicEndOfFile();
    if (FAILED(ec)) return 0;

    return 1;
}

Void Close(Int32 nFilehandler)
{
    if (nFilehandler < 0 || s_nFileObject[nFilehandler] == 0) return;

    BasicIO *pBasicIO = (BasicIO *)(s_nFileObject[nFilehandler]);
    delete pBasicIO;

    FreeFileHandler(nFilehandler);
}

UInt32 GetElapsedTime()
{
    DzGetSystemTime(&s_SystemTime);

    s_n64ThisTime = s_SystemTime.seconds * 1000000 + s_SystemTime.microseconds;
    s_nElapsedTime = (UInt32)((s_n64ThisTime - s_n64LastTime) / 1000);
    s_n64LastTime = s_n64ThisTime;

    return s_nElapsedTime;
}

ECode KeyWriteAt(Byte *pKeyData)
{
    s_pIMutex->Lock(&s_WaitResult);

    UInt32 uDelay = GetElapsedTime();

    Write((Byte *)&s_nDeviceKeyboard, 1, 1, s_fhScript);
    Write((Byte *)pKeyData, sizeof(KPDData), 1, s_fhScript);
    Write((Byte *)&uDelay, sizeof(UInt32), 1, s_fhScript);

    s_pIMutex->Unlock();

    if (((KPDData *)pKeyData)->keycode == VK_VOLUME_DOWN) {
        Close(s_fhScript);
        s_fhScript = -1;
        s_uTestType = TestType_Common;
    }

    return NOERROR;
}

ECode StylusWriteAt(Byte *pMouseData)
{
    s_pIMutex->Lock(&s_WaitResult);

    UInt32 uDelay = GetElapsedTime();

    Write((Byte *)&s_nDeviceMouse, 1, 1, s_fhScript);
    Write((Byte *)pMouseData, sizeof(TouchData), 1, s_fhScript);
    Write((Byte *)&uDelay, sizeof(UInt32), 1, s_fhScript);

    s_pIMutex->Unlock();

    return NOERROR;
}

ECode KeyReadAt(Byte *pBuffer)
{
    if (s_nDevice != s_nDeviceKeyboard) {
        s_pIEventKeyboard->Wait(&s_WaitResult, NULL);
        s_pIEventKeyboard->Clear();
        if (s_uTestType == TestType_Common) return NOERROR;
    }

    if (EndOfFile(s_fhScript)) {
        Close(s_fhScript);
        s_fhScript = -1;
        s_uTestType = TestType_Common;
        s_pIEventMouse->Notify(1);
        return NOERROR;
    }

    s_pIMutex->Lock(&s_WaitResult);

    UInt32 uDelay;

    Read((Byte *)pBuffer, sizeof(KPDData), 1, s_fhScript);
    Read((Byte *)&uDelay, sizeof(UInt32), 1, s_fhScript);
    Read((Byte *)&s_nDevice, 1, 1, s_fhScript);

    DzSleep(uDelay, NULL);

    if (s_nDevice == s_nDeviceMouse) {
        s_pIEventMouse->Notify(1);
    }

    s_pIMutex->Unlock();

    return NOERROR;
}

ECode StylusReadAt(Byte *pBuffer)
{
    if (s_nDevice != s_nDeviceMouse) {
        s_pIEventMouse->Wait(&s_WaitResult, NULL);
        s_pIEventMouse->Clear();
        if (s_uTestType == TestType_Common) return NOERROR;
    }

    if (EndOfFile(s_fhScript)) {
        s_uTestType = TestType_Common;
        s_pIEventKeyboard->Notify(1);
        return NOERROR;
    }

    s_pIMutex->Lock(&s_WaitResult);

    UInt32 uDelay;

    Read((Byte *)pBuffer, sizeof(TouchData), 1, s_fhScript);
    Read((Byte *)&uDelay, sizeof(UInt32), 1, s_fhScript);
    Read((Byte *)&s_nDevice, 1, 1, s_fhScript);

    DzSleep(uDelay, NULL);

    if (s_nDevice == s_nDeviceKeyboard) {
        s_pIEventKeyboard->Notify(1);
    }

    s_pIMutex->Unlock();

    return NOERROR;
}

//
// CaptureFrame
//

typedef struct tagBitmapFileHeader {
    Int32 bfSize;
    Int16 bfReserved1;
    Int16 bfReserved2;
    Int32 bfOffBits;
} BitmapFileHeader;

typedef struct tagBitmapInfoHeader {
    Int32 biSize;
    Int32 biWidth;
    Int32 biHeight;
    Int16 biPlanes;
    Int16 biBitCount;
    Int32 biCompression;
    Int32 biSizeImage;
    Int32 biXPelsPerMeter;
    Int32 biYPelsPerMeter;
    Int32 biClrUsed;
    Int32 biClrImportant;
} BitmapInfoHeader;

//Capture single frame start

static Void WriteSingleBmpHeader(
        Int32 fp,
        ColorFormat uColorFormat,
        Int32 nBpp,
        Int32 nWidth,
        Int32 nHeight)
{
    BitmapFileHeader bitmapFileHeader = {0};
    BitmapInfoHeader bitmapInfoHeader = {0};

    bitmapFileHeader.bfSize = 2 + sizeof(BitmapFileHeader)
        + sizeof(BitmapInfoHeader) + ((nBpp * nWidth * nHeight) >> 3);
    bitmapFileHeader.bfOffBits = 2 + sizeof(BitmapFileHeader)
        + sizeof(BitmapInfoHeader);

    bitmapInfoHeader.biSize = sizeof(BitmapInfoHeader);
    bitmapInfoHeader.biWidth = nWidth;
    bitmapInfoHeader.biHeight = nHeight;
    bitmapInfoHeader.biPlanes = 1;
    bitmapInfoHeader.biBitCount = nBpp;
    bitmapInfoHeader.biSizeImage = (nBpp * nWidth * nHeight) >> 3;

    if (nBpp == 16 || nBpp == 32) {
        bitmapFileHeader.bfSize += 12;
        bitmapFileHeader.bfOffBits += 12;
        bitmapInfoHeader.biCompression = 3;
    }

    Write((Byte *)("BM"), 2, 1, fp);
    Write((Byte *)&bitmapFileHeader, sizeof(BitmapFileHeader), 1, fp);
    Write((Byte *)&bitmapInfoHeader, sizeof(BitmapInfoHeader), 1, fp);

    Int32 rgbQuad[3];

    if (nBpp == 16) {
        if (uColorFormat == COLOR_RGB565) {
            rgbQuad[0] = 0x0000F800;
            rgbQuad[1] = 0x000007E0;
            rgbQuad[2] = 0x0000001F;
            Write((Byte *)rgbQuad, sizeof(rgbQuad), 1, fp);

        }
    }
    else if (nBpp == 32) {
        if (uColorFormat == COLOR_RGBT666) {
            rgbQuad[0] = 0x0003F000;
            rgbQuad[1] = 0x00000FC0;
            rgbQuad[2] = 0x0000003F;
            Write((Byte *)rgbQuad, sizeof(rgbQuad), 1, fp);
        }
    }
}

ECode InitSingleBuffer()
{
    ECode ec = NOERROR;
    MemoryBuf_<32> mbAddress;
    MemoryBuf_ < sizeof(FrameBufferFormat) > mbFormat;
    IDeviceDriver *pIBaseplane = NULL;
    FrameBufferFormat *fbFormat = NULL;

    ec = DzFindService(L"device:display0", (PInterface *)&pIBaseplane);
    if (FAILED(ec)) return ec;

    ec = pIBaseplane->Control(3, NULL_MEMORYBUF, &mbAddress, NULL);
    if (FAILED(ec)) goto __DoExit__;

    s_pSingleFrameBuffer = (Address *)*(Address *)mbAddress.GetPayload();

    ec = pIBaseplane->Control(7, NULL_MEMORYBUF, &mbFormat, NULL);
    if (FAILED(ec)) goto __DoExit__;

    fbFormat = (FrameBufferFormat *)mbFormat.GetPayload();
    s_nSinglePitch = (fbFormat->Width * fbFormat->Bpp) >> 3;
    s_nSingleFrameSize = (fbFormat->Bpp * fbFormat->Width * fbFormat->Height) >> 3;
    s_nSingleHeight = fbFormat->Height;

    s_pSingleCaptureBuffer = (Address *)malloc(s_nSingleFrameSize);
    if (!s_pSingleCaptureBuffer) {
        return E_OUT_OF_MEMORY;
    }

__DoExit__:
    if (pIBaseplane) pIBaseplane->Release();

    return ec;
}

ECode CaptureSingleFrame()
{
    Int32 nIndex = 0;

    for (nIndex = s_nSingleHeight - 1; nIndex >= 0; nIndex--) {
        memcpy(
            (Byte *)s_pSingleCaptureBuffer + nIndex * s_nSinglePitch,
            (Byte *)s_pSingleFrameBuffer + (s_nSingleHeight - nIndex - 1) * s_nSinglePitch,
            s_nSinglePitch
        );
    }

    s_nSingleFrameIndex++;

    return NOERROR;
}

ECode OutputSingleFrame()
{
    kprintf("**************** Begin Output Single Frame ***************\n");

    WChar wszTemp[64];
    WChar TempStr[20];

#ifdef _win32
    SYSTEMTIME localTime;
    GetLocalTime(&localTime);
    Int32 nLength = swprintf(wszTemp, L"%04d%02d%02d%02d%02d%02d",
        localTime.wYear, localTime.wMonth, localTime.wDay,
        localTime.wHour, localTime.wMinute, localTime.wSecond);
#else
    SystemTime sysTime;
    DzGetSystemTime(&sysTime);
    itowchar(sysTime.seconds + sysTime.microseconds / 1000000, TempStr, 10);
    wcscpy(wszTemp, TempStr);
#endif

// Create captured picture containing folder name

    if (s_nPicFolderCount != s_nSingleFrameIndex / 50) {
        wcscpy(s_wPicFolderName, TempStr);
    }

    wcscat(wszTemp, L"_");
    itowchar(s_nSingleFrameIndex, TempStr, 10);
    wcscat(TempStr, L".bmp");
    wcscat(wszTemp, TempStr);

    ECode ec = NOERROR;
    FrameBufferFormat *fbFormat = NULL;
    IDeviceDriver *pIBaseplane = NULL;
    MemoryBuf_ < sizeof(FrameBufferFormat) > mbFormat;

    ec = DzFindService(L"device:display0", (PInterface *)&pIBaseplane);
    if (FAILED(ec)) return ec;

    ec = pIBaseplane->Control(7, NULL_MEMORYBUF, &mbFormat, NULL);
    if (FAILED(ec)) {
        pIBaseplane->Release();
        return ec;
    }

    pIBaseplane->Release();

    fbFormat = (FrameBufferFormat *)mbFormat.GetPayload();

    Int32 CaptureSingleFrame = Open(wszTemp, OpenMode_RW);

    if (CaptureSingleFrame >= 0) {
        WriteSingleBmpHeader(CaptureSingleFrame, fbFormat->Color,
                      fbFormat->Bpp, fbFormat->Width, fbFormat->Height);
        Write((Byte *)s_pSingleCaptureBuffer, s_nSingleFrameSize, 1, CaptureSingleFrame);
        Close(CaptureSingleFrame);
    }
    CaptureSingleFrame = -1;

    kprintf("**************** End Output Single Frame ***************\n");

    return NOERROR;
}

Void GeneralFrameFile()
{
    ECode ec = NOERROR;

    ec = CaptureSingleFrame();
    if (FAILED(ec)) {
        kprintf("CaptureSingleFrame Error \n");
        return;
    }

    ec = OutputSingleFrame();
    if (FAILED(ec)) {
        kprintf("OutputSingleFrame Error \n");
        return;
    }
}
//Capture single frame end
//************************

#ifdef _CAPTURE_FRAME_

#ifdef _win32

static Address** s_ppCaptureBuffer = NULL;
static Address* s_pFrameBuffer = NULL;
static Int32 s_nCaptureLength = 0;
static Int32 s_nFrameIndex = 0;
static Int32 s_nFrameSize = 0;
static Int32 s_nPitch = 0;
static Int32 s_nHeight = 0;
static Int32 s_nStackFrame = 0;

ECode InitCaptureBuffer(Int32 nLength)
{
    if (nLength == 0) return NOERROR;

    ECode ec = NOERROR;
    IDeviceDriver *pIBaseplane = NULL;

    Int32 nIndex = 0;

    MemoryBuf_< 32 > mbAddress;
    MemoryBuf_< sizeof(FrameBufferFormat) > mbFormat;
    FrameBufferFormat *pFormat = NULL;

    ec = DzFindService(L"device:display0", (PInterface *)&pIBaseplane);
    if (FAILED(ec)) return ec;

    ec = pIBaseplane->Control(3, NULL_MEMORYBUF, &mbAddress, NULL);
    if (FAILED(ec)) goto __DoExit__;

    s_pFrameBuffer = (Address *)*(Address *)mbAddress.GetPayload();

    ec = pIBaseplane->Control(7, NULL_MEMORYBUF, &mbFormat, NULL);
    if (FAILED(ec)) goto __DoExit__;

    pFormat = (FrameBufferFormat *)mbFormat.GetPayload();

    s_nPitch = (pFormat->Width * pFormat->Bpp) >> 3;
    s_nFrameSize = (pFormat->Bpp * pFormat->Width * pFormat->Height) >> 3;
    s_nHeight = pFormat->Height;

    s_ppCaptureBuffer = (Address **)malloc(nLength * 4);
    memset(s_ppCaptureBuffer, 0, nLength * 4);

    for (nIndex = 0; nIndex < nLength; nIndex++) {
        s_ppCaptureBuffer[nIndex] = (Address *)malloc(s_nFrameSize);
        if (!s_ppCaptureBuffer[nIndex]) break;
    }

    s_nCaptureLength = nIndex;

__DoExit__:
    if (pIBaseplane) pIBaseplane->Release();

    return ec;
}

static Void WriteBmpHeader(
    FILE * fp,
    ColorFormat uColorFormat,
    Int32 nBpp,
    Int32 nWidth,
    Int32 nHeight)
{
    BitmapFileHeader bitmapFileHeader = { 0 };
    BitmapInfoHeader bitmapInfoHeader = { 0 };

    bitmapFileHeader.bfSize = 2 + sizeof(BitmapFileHeader)
        + sizeof(BitmapInfoHeader) + ((nBpp * nWidth * nHeight) >> 3);
    bitmapFileHeader.bfOffBits = 2 + sizeof(BitmapFileHeader)
        + sizeof(BitmapInfoHeader);

    bitmapInfoHeader.biSize = sizeof(BitmapInfoHeader);
    bitmapInfoHeader.biWidth = nWidth;
    bitmapInfoHeader.biHeight = nHeight;
    bitmapInfoHeader.biPlanes = 1;
    bitmapInfoHeader.biBitCount = nBpp;
    bitmapInfoHeader.biSizeImage = (nBpp * nWidth * nHeight) >> 3;

    if (nBpp == 16 || nBpp == 32) {
        bitmapFileHeader.bfSize += 12;
        bitmapFileHeader.bfOffBits += 12;
        bitmapInfoHeader.biCompression = 3;
    }

    fwrite("BM", 2, 1, fp);
    fwrite(&bitmapFileHeader, sizeof(BitmapFileHeader), 1, fp);
    fwrite(&bitmapInfoHeader, sizeof(BitmapInfoHeader), 1, fp);

    Int32 rgbQuad[3];

    if (nBpp == 16) {
        if (uColorFormat == COLOR_RGB565) {
            rgbQuad[0] = 0x0000F800;
            rgbQuad[1] = 0x000007E0;
            rgbQuad[2] = 0x0000001F;
            fwrite(rgbQuad, sizeof(rgbQuad), 1, fp);
        }
    }
    else if (nBpp == 32) {
        if (uColorFormat == COLOR_RGBT666) {
            rgbQuad[0] = 0x0003F000;
            rgbQuad[1] = 0x00000FC0;
            rgbQuad[2] = 0x0000003F;
            fwrite(rgbQuad, sizeof(rgbQuad), 1, fp);
        }
    }
}

ECode CaptureFrame()
{
    if (s_nCaptureLength == 0) return NOERROR;

    if (s_nFrameIndex >= s_nCaptureLength) s_nFrameIndex = 0;

    Int32 nIndex = 0;

    for (nIndex = s_nHeight - 1; nIndex >= 0; nIndex--) {
        memcpy(
            (Byte *)s_ppCaptureBuffer[s_nFrameIndex] + nIndex * s_nPitch,
            (Byte *)s_pFrameBuffer + (s_nHeight - nIndex - 1) * s_nPitch,
            s_nPitch
        );
    }

    s_nFrameIndex++;

    return NOERROR;
}

ECode OutputFrames()
{
    if (s_nCaptureLength == 0) return NOERROR;

    SYSTEMTIME localTime;
    GetLocalTime(&localTime);

    WChar wszTemp[64];
    WChar *pwszTemp = wszTemp;

    Int32 nLength = swprintf(wszTemp, L"%04d%02d%02d%02d%02d%02d",
        localTime.wYear, localTime.wMonth, localTime.wDay,
        localTime.wHour, localTime.wMinute, localTime.wSecond);

    Int32 nFrameIndex = 0x30;
    Int32 nIndex = s_nFrameIndex;
    FILE *fpBitmap = NULL;

    ECode ec = NOERROR;
    IDeviceDriver *pIBaseplane = NULL;
    MemoryBuf_< sizeof(FrameBufferFormat) > mbFormat;

    ec = DzFindService(L"device:display0", (PInterface *)&pIBaseplane);
    if (FAILED(ec)) return ec;

    ec = pIBaseplane->Control(7, NULL_MEMORYBUF, &mbFormat, NULL);
    if (FAILED(ec)) {
        pIBaseplane->Release();
        return ec;
    }

    pIBaseplane->Release();

    FrameBufferFormat *pFormat = (FrameBufferFormat *)mbFormat.GetPayload();

    for (nIndex = s_nFrameIndex; nIndex < s_nCaptureLength; nIndex++)
    {
        pwszTemp = wszTemp + nLength;

        *pwszTemp++ = nFrameIndex++;
        wcscpy(pwszTemp, L".bmp");

        fpBitmap = _wfopen(wszTemp, L"wb");

        WriteBmpHeader(fpBitmap, pFormat->Color,
            pFormat->Bpp, pFormat->Width, pFormat->Height);

        fwrite(s_ppCaptureBuffer[nIndex], s_nFrameSize, 1, fpBitmap);
        fclose(fpBitmap);
    }

    for (nIndex = 0; nIndex < s_nFrameIndex; nIndex++)
    {
        pwszTemp = wszTemp + nLength;

        *pwszTemp++ = nFrameIndex++;
        wcscpy(pwszTemp, L".bmp");

        fpBitmap = _wfopen(wszTemp, L"wb");

        WriteBmpHeader(fpBitmap, pFormat->Color,
            pFormat->Bpp, pFormat->Width, pFormat->Height);

        fwrite(s_ppCaptureBuffer[nIndex], s_nFrameSize, 1, fpBitmap);
        fclose(fpBitmap);
    }

    return NOERROR;
}

#endif // _CAPTURE_FRAME_

#endif // _win32

//
// AutoTest
//
Int32 GetRandNumber(Void)
{
    if (s_nRandSeed == 0) s_nRandSeed = 123459876;

    Int32 nHigh = s_nRandSeed / 127773;
    Int32 nLow = s_nRandSeed % 127773;

    Int32 nNumber = 16807 * nLow - 2836 * nHigh;
    if (nNumber < 0) nNumber += 0x7fffffff;

    return ((s_nRandSeed = nNumber) % ((UInt32)32767 + 1));
}

Void ParseInfoLine(AChar *pszLine)
{
    AChar *pszTemp = NULL;

    if (_strnicmp(pszLine, "AutoTestSpeed", 13) == 0) {
        pszTemp = pszLine + 14;

        Int32 nAutoTestSpeed = atoi(pszTemp);

        if (nAutoTestSpeed > 0 && nAutoTestSpeed < 10000) {
            s_nRandSpeed = nAutoTestSpeed;
        }
    }
    else if (_strnicmp(pszLine, "AutoTestShowTime", 16) == 0) {
        pszTemp = pszLine + 17;

        Int32 nAutoTestShowTime = atoi(pszTemp);

        if (nAutoTestShowTime > 0) {
            s_nShowTime = nAutoTestShowTime;
        }
    }
    else if (_strnicmp(pszLine, "AutoTestStartTime", 17) == 0) {
        pszTemp = pszLine + 18;

        Int32 nAutoTestStartTime = atoi(pszTemp);

        if (nAutoTestStartTime > 0) {
            s_nStartTime = nAutoTestStartTime;
        }
    }
#ifdef _CAPTURE_FRAME_
    else if (_strnicmp(pszLine, "AutoTestStackFrame", 18) == 0) {
        pszTemp = pszLine + 19;

        Int32 nAutoTestStackFrame = atoi(pszTemp);

        if (nAutoTestStackFrame > 0) {
            s_nStackFrame = nAutoTestStackFrame;
        }
    }
#endif // _CAPTURE_FRAME_
    else if (_strnicmp(pszLine, "VK_", 3) == 0) {
        pszTemp = pszLine + 3;

        switch (*pszTemp) {
            case 'C' :
                if (_strnicmp(pszTemp, "CAMERA", 6) == 0) {
                    s_nKey[s_nMaxKey++] = VK_CAMERA;
                }
            break;

            case 'V' :
                if (_strnicmp(pszTemp, "VOLUME_UP", 9) == 0) {
                    s_nKey[s_nMaxKey++] = VK_VOLUME_UP;
                }
                else if (_strnicmp(pszTemp, "VOLUME_DOWN", 11) == 0) {
                    s_nKey[s_nMaxKey++] = VK_VOLUME_DOWN;
                }
            break;

            case 'P' :
                if (_strnicmp(pszTemp, "PHONE_CALL", 10) == 0) {
                    s_nKey[s_nMaxKey++] = VK_PHONE_CALL;
                }
                else if (_strnicmp(pszTemp, "PHONE_HANG_UP", 13) == 0) {
                    s_nKey[s_nMaxKey++] = VK_PHONE_HANG_UP;
                }
            break;

            case 'H' :
                if (_strnicmp(pszTemp, "HOME", 4) == 0) {
                    s_nKey[s_nMaxKey++] = VK_HOME;
                }
            break;

            default : break;
        }
    }
    else if (_strnicmp(pszLine, "AutoTestSpaceTime", 17) == 0) {
        pszTemp = pszLine + 18;

        Int32 nAutoTestSpaceTime = atoi(pszTemp) * 60;

        if (nAutoTestSpaceTime > 0) {
            s_nSpaceTime = nAutoTestSpaceTime;
        }
    }
}

#ifdef _win32

Void LogExceptionTime(Exception uTestState)
{
    SYSTEMTIME localTime;
    GetLocalTime(&localTime);

    FILE *fp = _wfopen(L"AutoTestTiming.txt", L"a+");
    if (!fp) return ;

    WChar *pwszPrefix = L"\n[StartTime :";

    switch (uTestState) {
        case Exception_Debugger :
            pwszPrefix = L"[DebuggerTime :";
        break;

        case Exception_Deadlock :
            pwszPrefix = L"[DeadlockTime :";
        break;

        case Exception_EventFull :
            pwszPrefix = L"[EventFullTime :";
        break;

        case Exception_OutOfMemory :
            pwszPrefix = L"[OutOfMemoryTime :";
        break;

        default : break;
    }

    fwprintf(fp, L"%s %04d-%02d-%02d %02d:%02d:%02d]\n", pwszPrefix,
        localTime.wYear, localTime.wMonth, localTime.wDay,
        localTime.wHour, localTime.wMinute, localTime.wSecond);

    fclose(fp);
}

ECode CheckDebuggerService(Boolean bIsTerminate)
{
    Int32 aProcesses[512], cbNeeded, cProcesses, hProcess, hModule;
    AChar szProcessName[16];

    EnumProcesses(aProcesses, 512, &cbNeeded);

    cProcesses = cbNeeded >> 2;

    for (Int32 i = 0; i < cProcesses; i++ ) {
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
            false, aProcesses[i]);

        if (hProcess) {
            if (EnumProcessModules(hProcess, &hModule, 4, &cbNeeded)) {

                GetModuleBaseNameA(hProcess, hModule, szProcessName, 16);

                switch (szProcessName[0]) {
                    case 'd':
                    case 'D':
                    case 'v':
                    case 'V':
                        break;

                    default:
                        CloseHandle(hProcess);
                        continue;
                }

                if (_strnicmp(szProcessName, "drwtsn32", 8) == 0
                    || _strnicmp(szProcessName, "vsjitDebugger", 13) == 0) {

                    if (bIsTerminate) {
                        TerminateProcess(hProcess, 0);
                        return NOERROR;
                    }

                    CloseHandle(hProcess);

                    g_bIsDebugger = true;

                    LogExceptionTime(Exception_Debugger);

                    s_pStack->Dump();
                    g_bufferCache.Dump();

                    if (s_pTimerRunning) {
                        s_pTimerRunning->Stop();
                    }

                    if (s_pTimerDebugger) {
                        s_pTimerDebugger->Stop();
                    }

                    kprintf(">>>--- Start Debugger ---<<<\n");

                    return NOERROR;
                }
            }
        }

        CloseHandle(hProcess);
    }

    return NOERROR;
}

ECode OnTimerRunning(PVoid pData, IActiveTimer *pITimer)
{
    if (!s_bRandomEvent) return NOERROR;

    s_nTotalTime++;

    kprintf(">>>--- Elapse %d minutes ---<<<\n", s_nTotalTime);

    return NOERROR;
}

ECode OnTimerDebugger(PVoid pData, IActiveTimer *pITimer)
{
    return CheckDebuggerService(false);
}

ECode OnTimerReplay(PVoid pData, IActiveTimer *pITimer)
{
    if (s_uTestType != TestType_Replay || s_fhScript < 0) {
        return NOERROR;
    }

    Read((Byte *)&s_nDevice, 1, 1, s_fhScript);

    switch (s_nDevice) {
        case s_nDeviceMouse :
            s_pIEventMouse->Notify(1);
        break;

        case s_nDeviceKeyboard :
            s_pIEventKeyboard->Notify(1);
        break;
    }

    s_pTimerReplay->Stop();

    return NOERROR;
}

#else // _win32

Void ShowMemoryState()
{
    StatInfo statInfo;
    GetStatInfo(&statInfo);

    kprintf(
        "\n-----------------------------------------------------------\n"
        "Cache: Alloced bytes = %d, Total pages = %d                \n\n"
        "Pages: Alloced kernel pages = %d, AllocedPhysicsPages = %d \n\n"
        "Total pages = %d, Free pages = %d                          \n"
        "-----------------------------------------------------------\n\n",
        statInfo.uAllocedBytesOfCache, statInfo.uTotalPagesOfCache,
        statInfo.uAllocedKernelPages, statInfo.uAllocedPhysicsPages,
        statInfo.uTotalPages, statInfo.uFreePages);
}

Void OnTimerRunning(PVoid pData)
{
    s_pTimerRunning->Restart(DzMillisecondsToTicks(s_nShowTime * 1000));

    if (!s_bRandomEvent) return;

    s_nTotalTime++;

    kprintf(">>>--- Elapse %d minutes ---<<<\n", s_nTotalTime);

    ShowMemoryState();
}

#endif // _zener

Boolean GetPrameterInfo(WChar *pwszTemp, WChar *pwszInfo)
{
    if (*pwszTemp++ != L':') return false;

    while (*pwszTemp && (*pwszTemp == 0x20 || *pwszTemp == 0x09)) pwszTemp++;

    Int32 nCount = 0;
    while (*pwszTemp && *pwszTemp != 0x20 && *pwszTemp != 0x09)
        pwszInfo[nCount++] = *pwszTemp++;
    pwszInfo[nCount] = 0;

    return true;
}

ECode InitTestType()
{
    ECode ec = NOERROR;
    IProcess *pIProcess = NULL;
    IObjectEnumerator *pIObjEnum = NULL;

    WStringBuf *pwsbName = WStringBuf::Alloc(64);
    WStringBuf *pwsbArgs = WStringBuf::Alloc(256);
    WChar *pwszInfo = pwsbName->GetPayload();
    WChar *pwszTemp = NULL;
    WChar *pwszScript = (WChar *)malloc(256);
    Boolean bIsSucceed = false;

    Int32 nTestType = 0;

    Byte pbScriptTag[17];
    AChar *pTagRegular = TAG_REGULAT, *pTagRandom = TAG_RANDOM;

#ifdef _win32
    ec = CSystem::GetAllProcesses(&pIObjEnum);
    if (FAILED(ec)) goto __DoError__;
#else // _win32
    if (g_pCKernel) {
        ec = g_pCKernel->GetAllProcesses(&pIObjEnum);
        if (FAILED(ec)) goto __DoError__;
    }
#endif // _zener

    while (true) {
        ec = pIObjEnum->MoveNext(&bIsSucceed);
        if (FAILED(ec) || !bIsSucceed) break;

        pIObjEnum->Current((PInterface *)&pIProcess);
        pIProcess->GetStartInfo(pwsbName, pwsbArgs);

        if (_wcsnicmp(pwsbName->GetPayload(), L"superexe.exe", 12) == 0) {
            pIProcess->Release();
            break;
        }

        pIProcess->Release();
    }

    pwszTemp = pwsbArgs->GetPayload();
    while (*pwszTemp) {
        if (*pwszTemp++ != '/') continue;

        switch (*pwszTemp++) {
            case 'T' :
            case 't' :
                if (!GetPrameterInfo(pwszTemp, pwszInfo)) break;

                nTestType = _wtoi(pwszInfo);
                if (nTestType > TestType_Common
                    && nTestType < TestType_Undefined) {
                    s_uTestType = (TestType)nTestType;
                }
            break;

            case 'F' :
            case 'f' :
                if (!GetPrameterInfo(pwszTemp, pwszInfo)) break;
                wcscpy(pwszScript, pwszInfo);
            break;
        }
    };

    switch (s_uTestType) {
        case TestType_Record :
            s_fhScript = Open(pwszScript, OpenMode_RW);
            if (s_fhScript >= 0) {
                Write((Byte *)pTagRegular, 1, 17, s_fhScript);
            }
            else {
                s_uTestType = TestType_RandomReplay;
            }
        break;

        case TestType_Replay :
            s_fhScript = Open(pwszScript, OpenMode_ReadOnly);
            if (s_fhScript >= 0) {
                Read(pbScriptTag, 1, 17, s_fhScript);

                if (strncmp((AChar *)pbScriptTag, pTagRegular, 17) != 0) {
                    s_uTestType = TestType_RandomReplay;
                    Close(s_fhScript);
                    s_fhScript = -1;
                }
            }
            else {
                s_uTestType = TestType_RandomReplay;
            }
        break;

        case TestType_RecordRandomEvent :
            s_fhScript = Open(pwszScript, OpenMode_RW);
            if (s_fhScript >= 0) {
                Write((Byte *)pTagRandom, 1, 17, s_fhScript);
            }
            else {
                s_uTestType = TestType_RandomReplay;
            }
        break;

        case TestType_ReplayRandomEvent :
            s_fhScript = Open(pwszScript, OpenMode_ReadOnly);
            if (s_fhScript >= 0) {
                Read(pbScriptTag, 1, 17, s_fhScript);

                if (strncmp((AChar *)pbScriptTag, pTagRandom, 17) != 0) {
                    s_uTestType = TestType_RandomReplay;
                    Close(s_fhScript);
                    s_fhScript = -1;
                }
            }
            else {
                s_uTestType = TestType_RandomReplay;
            }
        break;

        default : break;
    }

__DoError__:
    if (pIObjEnum) pIObjEnum->Release();
    if (pwsbName) WStringBuf::Free(pwsbName);
    if (pwsbArgs) WStringBuf::Free(pwsbArgs);
    if (pwszScript) free(pwszScript);

    return ec;
}

ECode InitRegularEnv()
{
    ECode ec = NOERROR;

    if (!s_pIMutex) {
#ifdef _win32
        ec = CMutex::New(&s_pIMutex);
        if (FAILED(ec)) return ec;
#else // _win32
        CMutex *pCMutex = new CMutex;
        s_pIMutex = (IMutex *)pCMutex;
#endif // _zener
    }

    if (!s_pIEventMouse) {
        ec = DzCreateEventObj(1, 0, &s_pIEventMouse);
        if (FAILED(ec)) return ec;
    }

    if (!s_pIEventKeyboard) {
        ec = DzCreateEventObj(1, 0, &s_pIEventKeyboard);
        if (FAILED(ec)) return ec;
    }

#ifdef _win32
    if (!s_pTimerReplay) {
        CActiveTimer::New(s_nStartTime * 1000, OnTimerReplay,
            (PVoid)NULL, &s_pTimerReplay);
    }

    if (s_pTimerReplay) {
        s_pTimerReplay->Start();
    }
#endif // _win32

    GetElapsedTime();

    return ec;
}

ECode InitRandomEnv()
{
    ECode ec = NOERROR;

    if (!s_pIEvent) {
        ec = DzCreateEventObj(0, 0, &s_pIEvent);
        if (FAILED(ec)) return ec;
    }

#ifdef _win32
    if (!s_pTimerRunning) {
        CActiveTimer::New(60 * 1000, OnTimerRunning,
            (PVoid)NULL, &s_pTimerRunning);
    }

    if (s_pTimerRunning) {
        s_pTimerRunning->Start();
    }

    if (!s_pTimerDebugger) {
        CActiveTimer::New(5000, OnTimerDebugger,
            (PVoid)NULL, &s_pTimerDebugger);
    }

    if (s_pTimerDebugger) {
        s_pTimerDebugger->Start();
    }

    LogExceptionTime(Exception_Normal);

#else // _win32
    UInt32 uTicks = DzMillisecondsToTicks(60 * 1000);
    if (!s_pTimerRunning) {
        s_pTimerRunning = new DzTimer(uTicks, OnTimerRunning, NULL);
    }

    if (s_pTimerRunning) {
        s_pTimerRunning->Start();
    }
#endif // _zener

#ifdef _win32

//    SystemTime sysTime;
//    DzGetSystemTime(&sysTime);
//
//    s_nRandSeed = sysTime.seconds + sysTime.microseconds + nTicks;
//    if (s_nRandSeed < 0) s_nRandSeed += 0x7fffffff;

    LARGE_INTEGER TimingCounter;
    QueryPerformanceCounter(&TimingCounter);

    s_nRandSeed = (Int32)(TimingCounter.QuadPart % 0x7FFFFFFF);

    kprintf("*RANDOM-SEED*: %x\n", s_nRandSeed);

#else // _win32

    Address timingAddr;
    UInt32 uTicksTemp = (Int32)&timingAddr;

    ec = DzIoRemap(0, 4096, 0x40A00000,
        MemoryMap_Private, IoRemapFlag_BufferedWrite, &timingAddr);
    if (SUCCEEDED(ec)) {
        uTicksTemp = (*(UInt32 *)(timingAddr + 0x10));
        DzIoUnmap(timingAddr, 4096);
    }

    SystemTime sysTime;
    DzGetSystemTime(&sysTime);

    s_nRandSeed = sysTime.seconds + sysTime.microseconds + uTicksTemp;
    if (s_nRandSeed < 0) s_nRandSeed += 0x7fffffff;

    kprintf("*RANDOM-SEED*: %x:%x:%x:%x\n",
        sysTime.seconds, sysTime.microseconds, uTicksTemp,
        sysTime.seconds + sysTime.microseconds + uTicksTemp);
#endif // _zener

    return ec;
}

ECode AnalyzeConfig()
{
    ECode ec = NOERROR;
    Int32 nFileSize = 0;
    Int32 nFileHandler = 0;
    AChar *pszTemp = NULL, *pszLine = NULL;
    Int32 nCount = 0;
    Byte *pBuffer = NULL;

    pszLine = (AChar *)malloc(256);
    if (!pszLine) goto __DoExit__;

    nFileHandler = Open(L"vinci.cfg", OpenMode_ReadOnly);
    if (nFileHandler == -1) {
        s_bIsConfigExist = false;
        goto __DoExit__;
    }

    nFileSize = GetSize(nFileHandler);
    if (nFileSize == -1) goto __DoExit__;

    pBuffer = (Byte *)malloc(nFileSize + 1);

    ec = Read(pBuffer, 1, nFileSize, nFileHandler);
    if (FAILED(ec)) goto __DoExit__;

    pBuffer[nFileSize] = 0;

    pszTemp = (AChar *)pBuffer;
    while (*pszTemp) {
        if (*pszTemp == 0x0D || *pszTemp == 0x0A) {
            pszTemp++;
            continue;
        }
        else if (*pszTemp == '#') {
            while (*pszTemp && *pszTemp != 0X0D && *pszTemp != 0x0A) pszTemp++;
            continue;
        }
        else {
            nCount = 0;
            while (*pszTemp) {
                if (*pszTemp == 0x20 || *pszTemp == 0x09) pszTemp++;
                else if (*pszTemp == '#' || *pszTemp == 0x0D || *pszTemp == 0x0A) break;
                else pszLine[nCount++] = *pszTemp++;
            }
            pszLine[nCount] = 0;

            if (pszLine[0] == '#' || pszLine[0] == 0) continue;

            ParseInfoLine(pszLine);
        }
    };

__DoExit__:
    if (pszLine) free(pszLine);
    if (nFileHandler > 0) Close(nFileHandler);
    if (pBuffer) free(pBuffer);

    return ec;
}

Void AutoTestRelease()
{
    s_uTestType = TestType_RandomReplay;
    s_uTestState = TestState_Stopped;
    s_uException = Exception_Normal;
    s_pStack = NULL;
    s_nRandSpeed = 300;
    s_nMouseRatio = 60;
    s_nTotalTime = 0;
    s_nRandSeed = 0;
    s_nShowTime = 60;
    s_nStartTime = 60;
    s_bRandomEvent = false;
    g_bIsDebugger = false;
    g_bIsPauseRandomEvent = true;

    if (s_pIEvent) {
        s_pIEvent->Release();
        s_pIEvent = NULL;
    }

    //Capture single frame
    if (s_pSingleCaptureBuffer != NULL)
        free(s_pSingleCaptureBuffer);
    s_pSingleCaptureBuffer = NULL;
    s_pSingleFrameBuffer = NULL;
    s_nSingleFrameIndex = 0;
    s_nSingleFrameSize = 0;
    s_nSinglePitch = 0;
    s_nSingleHeight = 0;

#ifdef _win32
    if (s_pTimerRunning) {
        s_pTimerRunning->Stop();
        s_pTimerRunning->Release();
        s_pTimerRunning = NULL;
    }

    if (s_pTimerDebugger) {
        s_pTimerDebugger->Stop();
        s_pTimerDebugger->Release();
        s_pTimerDebugger = NULL;
    }

    if (s_pTimerReplay) {
        s_pTimerReplay->Stop();
        s_pTimerReplay->Release();
        s_pTimerReplay = NULL;
    }
#else // _win32
    if (s_pTimerRunning) {
        s_pTimerRunning->Cancel();
        delete s_pTimerRunning;
        s_pTimerRunning = NULL;
    }
#endif // _zener

    s_nDevice = 0;
    s_fhScript = -1;
    s_nEventIndex = 0;

    if (s_pIMutex) {
        s_pIMutex->Release();
        s_pIMutex = NULL;
    }

    if (s_pIEventMouse) {
        s_pIEventMouse->Release();
        s_pIEventMouse = NULL;
    }

    if (s_pIEventKeyboard) {
        s_pIEventKeyboard->Release();
        s_pIEventKeyboard = NULL;
    }

#ifdef _CAPTURE_FRAME_
    s_ppCaptureBuffer = NULL;
    s_pFrameBuffer = NULL;
    s_nCaptureLength = 0;
    s_nFrameIndex = 0;
    s_nFrameSize = 0;
    s_nPitch = 0;
    s_nHeight = 0;
    s_nStackFrame = 0;
#endif // _CAPTURE_FRAME_

}

ECode InitAutoTest()
{
    ECode ec = NOERROR;

    InitSingleBuffer();

    InitFileHandler();

    InitTestType();

#ifdef _win32
    CheckDebuggerService(true);
#endif // _win32

    AnalyzeConfig();

    switch (s_uTestType) {
        case TestType_Record :
        case TestType_Replay :
            ec = InitRegularEnv();
            if (FAILED(ec)) return ec;
        break;

        case TestType_RandomReplay :
        case TestType_RecordRandomEvent :
        case TestType_ReplayRandomEvent :

        #ifdef _CAPTURE_FRAME_
            InitCaptureBuffer(s_nStackFrame);
        #endif // _CAPTURE_FRAME_

            ec = InitRandomEnv();
            if (FAILED(ec)) return ec;
        break;

        default : break;
    }

    return ec;
}

Void CheckEventQueueState(ECode ec)
{
    if (SUCCEEDED(ec)) {
        if (ec == S_BUFFER_TOO_SMALL) {
            s_uException = Exception_EventFull;
        }
        else {
            s_uException = Exception_Normal;
        }
    }
}

Void GeneralStylusMoveEvent(GrafixObjectEvent& event, Boolean bIsMultiMovement)
{
    ECode ec = NOERROR;

    event.modifier = InputMask_LButton;

    if (bIsMultiMovement) {
        event.keyValue = GrafixObjectEventType_StylusMove;
        event.type = GrafixObjectEventType_MultiTouch;
    }
    else {
        event.type = GrafixObjectEventType_StylusMove;
    }

    Int32 nMouseMove = GetRandNumber() % MAX_MOUSE_MOVE;

    for (Int32 nIndex = 0; nIndex < nMouseMove; nIndex++) {
        switch (GetRandNumber() % 8) {
            case 0 :
                event.absoluteX += -1;
                event.absoluteY += -1;
            break;

            case 1 :
                event.absoluteX += -1;
                event.absoluteY += 0;
            break;

            case 2 :
                event.absoluteX += -1;
                event.absoluteY += 1;
            break;

            case 3 :
                event.absoluteX += 0;
                event.absoluteY += -1;
            break;

            case 4 :
                event.absoluteX += 0;
                event.absoluteY += 1;
            break;

            case 5 :
                event.absoluteX += 1;
                event.absoluteY += -1;
            break;

            case 6 :
                event.absoluteX += 1;
                event.absoluteY += 0;
            break;

            case 7 :
                event.absoluteX += 1;
                event.absoluteY += 1;
            break;
        }

        if (event.absoluteX < 0 || event.absoluteY < 0
            || event.absoluteX >= WIDTH || event.absoluteY >= HEIGHT) {
            continue;
        }

        ec = s_pStack->PostButtonEvent(event);
        CheckEventQueueState(ec);
    }
}

ECode GeneralStylusHeldEvent(Int32 nPosX, Int32 nPosY)
{
    if ((GetRandNumber() % 10) > 5) return -1;

    ECode ec = NOERROR;
    GrafixObjectEvent event;

    event.modifier = InputMask_LButton;
    event.absoluteX = nPosX;
    event.absoluteY = nPosY;

    event.type = GrafixObjectEventType_StylusHeld;
    ec = s_pStack->PostButtonEvent(event);
    CheckEventQueueState(ec);

#ifdef _MAKE_ALL_EVENTS_
    GeneralStylusMoveEvent(event, false);
#endif // _MAKE_ALL_EVENTS_

    event.type = GrafixObjectEventType_StylusReleased;
    ec = s_pStack->PostButtonEvent(event);
    CheckEventQueueState(ec);

    return NOERROR;
}

Void GeneralStylusEvent(Int32 nPosX, Int32 nPosY)
{
    ECode ec = NOERROR;
    GrafixObjectEvent event;

    event.modifier = InputMask_LButton;
    event.absoluteX = nPosX;
    event.absoluteY = nPosY;

    ec = g_lock.Lock();
    if (GFX_FAILED(ec)) return;

    event.type = GrafixObjectEventType_StylusPressed;
    ec = s_pStack->PostButtonEvent(event);
    CheckEventQueueState(ec);

#ifdef _MAKE_ALL_EVENTS_
    ec = GeneralStylusHeldEvent(nPosX, nPosY);
    if (SUCCEEDED(ec)) {
        CheckEventQueueState(ec);
        g_lock.Unlock();
        return ;
    }

    GeneralStylusMoveEvent(event, false);
#endif // _MAKE_ALL_EVENTS_

    event.type = GrafixObjectEventType_StylusLifted;
    ec = s_pStack->PostButtonEvent(event);
    CheckEventQueueState(ec);

    g_lock.Unlock();
}

ECode GeneralKeyHeldEvent(Int32 nKeyCode)
{
    if ((GetRandNumber() % 10) > 5) return -1;

    ECode ec = NOERROR;
    GrafixObjectEvent event;

    event.keyValue = nKeyCode;
    event.modifier = InputMask_None;

    event.type = GrafixObjectEventType_KeyHeld;
    ec = s_pStack->PostKeyEvent(event);
    CheckEventQueueState(ec);

    event.type = GrafixObjectEventType_KeyReleased;
    ec = s_pStack->PostKeyEvent(event);
    CheckEventQueueState(ec);

    return NOERROR;
}

Void GeneralKeyEvent(Int32 nKeyCode)
{
    ECode ec = NOERROR;
    GrafixObjectEvent event;

    event.keyValue = nKeyCode;
    event.modifier = InputMask_None;

    ec = g_lock.Lock();
    if (GFX_FAILED(ec)) return;

    event.type = GrafixObjectEventType_KeyDown;
    ec = s_pStack->PostKeyEvent(event);
    CheckEventQueueState(ec);

#ifdef _MAKE_ALL_EVENTS_
    ec = GeneralKeyHeldEvent(nKeyCode);
    if (SUCCEEDED(ec)) {
        CheckEventQueueState(ec);
        g_lock.Unlock();
        return ;
    }
#endif // _MAKE_ALL_EVENTS_

    event.type = GrafixObjectEventType_KeyUp;
    ec = s_pStack->PostKeyEvent(event);
    CheckEventQueueState(ec);

    g_lock.Unlock();
}

Void GeneralMultiTouchEvent()
{
    Int32 nPosX = GetRandNumber() % WIDTH;
    Int32 nPosY = GetRandNumber() % HEIGHT;

    GrafixObjectEvent event;
    ECode ec = NOERROR;

    ec = g_lock.Lock();
    if (GFX_FAILED(ec)) return;

    event.type = GrafixObjectEventType_MultiTouch;
    event.modifier = InputMask_LButton;
    event.absoluteX = nPosX;
    event.absoluteY = nPosY;
    event.fingers = 1;
    event.index = 0;

    event.keyValue = GrafixObjectEventType_StylusPressed;
    ec = s_pStack->PostButtonEvent(event);
    CheckEventQueueState(ec);

#ifdef _MAKE_ALL_EVENTS_
    GeneralStylusMoveEvent(event, true);
#endif // _MAKE_ALL_EVENTS_

    event.keyValue = GrafixObjectEventType_StylusLifted;
    ec = s_pStack->PostButtonEvent(event);
    CheckEventQueueState(ec);

    g_lock.Unlock();
}

CGrafixObject * GetStackTopGrafixObject()
{
    Void *pVector = NULL;
    CGrafixObject *pCGrafixObject = NULL;
    Int32 nIndex = 0;

    fusion_vector_foreach_reverse(pVector, nIndex, s_pStack->m_windows) {
        pCGrafixObject = (CGrafixObject *)pVector;

        if (pCGrafixObject->m_visible && pCGrafixObject->m_objId
            && !(pCGrafixObject->m_config.option & GrafixAttribute_Ghost)) {
            if (pCGrafixObject->m_title) {
                if (wcscmp(pCGrafixObject->m_title, L"StatusBar") != 0) {
                    return pCGrafixObject;
                }
            }
        }
    }

    return NULL;
}

CGrafixObject *GetMenuGrafixObject()
{
    Void *pVector = NULL;
    CGrafixObject *pCGrafixObject = NULL;
    Int32 nIndex = 0;

    fusion_vector_foreach_reverse(pVector, nIndex, s_pStack->m_windows) {
        pCGrafixObject = (CGrafixObject *)pVector;

        if (pCGrafixObject->m_visible && pCGrafixObject->m_objId
            && !(pCGrafixObject->m_config.option & GrafixAttribute_Ghost)) {
            if (pCGrafixObject->m_title) {
                if (wcscmp(pCGrafixObject->m_title, L"MainMenu") == 0
                    || wcscmp(pCGrafixObject->m_title, L"ChildMenu") == 0) {
                    return pCGrafixObject;
                }
            }
        }
    }

    return NULL;
}

Void RandStylus()
{
#ifdef _EVENTS_TO_STACKTOP_
    CGrafixObject *pCGrafixObject = GetStackTopGrafixObject();
    if (!pCGrafixObject) return ;

    Int32 nPosX, nPosY, nWidth, nHeight;

    pCGrafixObject->GetBounds(&nPosX, &nPosY, &nWidth, &nHeight);

    Int32 nScreenX = nPosX + GetRandNumber() % (WIDTH - nPosX);
    Int32 nScreenY = nPosY + GetRandNumber() % (HEIGHT - nPosY);
#else // _EVENTS_TO_STACKTOP_
    Int32 nScreenX = GetRandNumber() % WIDTH;
    Int32 nScreenY = GetRandNumber() % HEIGHT;

    CGrafixObject *pCGrafixObject = GetMenuGrafixObject();
    if (pCGrafixObject) {
        if (s_nEventToMenu < 20) {
            Int32 nPosX, nPosY, nWidth, nHeight;

            pCGrafixObject->GetBounds(&nPosX, &nPosY, &nWidth, &nHeight);

            kprintf("*OK* SendEventToMenu\n");

            s_nEventToMenu++;

            nScreenX = nPosX + GetRandNumber() % (WIDTH - nPosX);
            nScreenY = nPosY + GetRandNumber() % (HEIGHT - nPosY);
        }
    }
    else {
        if (s_nEventToMenu >= 20) {
            s_nEventToMenu = 0;
        }
    }
#endif // _EVENTS_TO_SCREEN_

    GeneralStylusEvent(nScreenX, nScreenY);

    if (s_uTestType == TestType_RecordRandomEvent) {
        s_pEventBuffer[s_nEventIndex] = nScreenX << 16 | nScreenY;

        if (++s_nEventIndex == EVENT_BUFFER_LENGTH) {
            Write((Byte *)s_pEventBuffer, 4, EVENT_BUFFER_LENGTH, s_fhScript);
            s_nEventIndex = 0;
        }
    }
}

Void RandKey()
{
    if (s_nMaxKey == 0) {
        if (!s_bIsConfigExist) {
            s_nMaxKey = sizeof(s_nKey) / sizeof(s_nKey[0]);
        }
        else {
            return ;
        }
    }

    Int32 nKeyCode = s_nKey[GetRandNumber() % s_nMaxKey];

    GeneralKeyEvent(nKeyCode);

    if (s_uTestType == TestType_RecordRandomEvent) {
        s_pEventBuffer[s_nEventIndex] = nKeyCode | 0xFFFF0000;

        if (++s_nEventIndex == EVENT_BUFFER_LENGTH) {
            Write((Byte *)s_pEventBuffer, 4, EVENT_BUFFER_LENGTH, s_fhScript);
            s_nEventIndex = 0;
        }
    }
}

Void ExceptionQuit()
{
    if (s_fhScript < 0) return ;

    if (s_nEventIndex > 0) {
        Write((Byte *)s_pEventBuffer, 4, s_nEventIndex, s_fhScript);
        s_nEventIndex = 0;
    }

    Close(s_fhScript);
    s_fhScript = -1;
    s_uTestType = TestType_Common;
}

Int32 GetTime()
{
    Int32 TempTime = 0;
#ifdef _win32
    SYSTEMTIME localTime;
    GetLocalTime(&localTime);
    TempTime = localTime.wHour* 360 + localTime.wMinute * 60 + localTime.wSecond;
#else
    SystemTime sysTime;
    DzGetSystemTime(&sysTime);
    TempTime = sysTime.seconds;
#endif
    return TempTime;
}

Void RandEvent()
{
    Int32 nEvent = 0, nPosX = 0, nPosY = 0, nOffsetIntervel = 0;
    WaitResult wr;

    if (s_uTestType != TestType_RandomReplay
        && s_uTestType != TestType_RecordRandomEvent
        && s_uTestType != TestType_ReplayRandomEvent) return ;

    kprintf(">>>-----------------------------------------<<<\n"
            ">>>--- Press VK_VOLUME_DOWN key to start ---<<<\n"
            ">>>-----------------------------------------<<<\n");

#ifdef _AUTO_START_

    if (s_nStartTime > 0) {

        s_uTestState = TestState_Waiting;

        kprintf(">>>--- Waiting %d seconds before start ---<<<\n",
            s_nStartTime);

#ifndef _win32
        s_pIEvent->TryWait(DzMillisecondsToTicks(
            s_nStartTime * 1000), &wr, NULL);
#else // _win32
        s_pIEvent->TryWait(s_nStartTime * 1000, &wr, NULL);
#endif // _zener

        s_bRandomEvent = true;
        g_bIsPauseRandomEvent = false;

        s_uTestState = TestState_Running;
    }

#endif // _AUTO_START_

    Int32 nStartTime =  GetTime();
    Int32 nFinishTime = nStartTime;

    for (;;) {
        if (!s_bRandomEvent) {
            s_pIEvent->Wait(&wr, NULL);
        }

        if (s_pStack->m_terminate) {
            return ;
        }

        if (g_bIsPauseRandomEvent) {
            s_pIEvent->Wait(&wr, NULL);
        }

        if (g_bIsDebugger) {

#ifndef _win32
            s_pTimerRunning->Cancel();
#endif // _win32
            ExceptionQuit();

#ifdef _CAPTURE_FRAME_
            OutputFrames();
#endif // _CAPTURE_FRAME_

            kprintf(">>>--- Fall into Debugger, finish ---<<<\n");

            return ;
        }

        if (s_uException == Exception_EventFull) {
            static Int32 s_nEventFull = 0;

            kprintf(">>>--- Event queue has overflowed ---<<<\n");

            if (s_nEventFull++ >= 512) {

            #ifdef _win32
                LogExceptionTime(Exception_EventFull);
                //ExceptionQuit();
            #endif // _win32

            }
        }

        switch (s_uTestType) {
            case TestType_RandomReplay :
            case TestType_RecordRandomEvent :

            #ifdef _CAPTURE_FRAME_
                CaptureFrame();
            #endif // _CAPTURE_FRAME_

            #ifdef _MAKE_ALL_EVENTS_
                if (GetRandNumber() % 9 == 0) {
                    GeneralMultiTouchEvent();
                }
            #endif // _MAKE_ALL_EVENTS_

                GetRandNumber() % 100 < s_nMouseRatio ? RandStylus() : RandKey();
            break;

            case TestType_ReplayRandomEvent :
                if (EndOfFile(s_fhScript)) {
                    Close(s_fhScript);
                    s_fhScript = -1;
                    s_uTestType = TestType_Common;

                    kprintf(">>>--- Finish replaying random script ---<<<\n");

                    return ;
                }

                Read((Byte *)&nEvent, 4, 1, s_fhScript);

                nPosX = nEvent >> 16 & 0xFFFF;
                nPosY = nEvent & 0xFFFF;

            #ifdef _CAPTURE_FRAME_
                CaptureFrame();
            #endif // _CAPTURE_FRAME_

                if (nPosX == 0xFFFF) {
                    GeneralKeyEvent(nPosY);
                }
                else {
                    GeneralStylusEvent(nPosX, nPosY);
                }
            break;

            default : break;
        }

        nFinishTime =  GetTime();
        if (nFinishTime < nStartTime) nStartTime = nFinishTime;
        if ((nFinishTime - nStartTime) > s_nSpaceTime) {
            nStartTime = nFinishTime;
            kprintf("**** Begin GeneralFrameFile()\n");
            GeneralFrameFile();
            kprintf("**** End GeneralFrameFile()\n");
#ifdef _zener

#endif  // _zener
        }

        nOffsetIntervel = GetRandNumber() % 80;

#ifdef _win32
        if (s_nRandSpeed < nOffsetIntervel) nOffsetIntervel = 0;
        DzSleep(s_nRandSpeed - nOffsetIntervel, NULL);
#else // _win32
        DzSleep(DzMillisecondsToTicks(s_nRandSpeed - nOffsetIntervel), NULL);
#endif // _zener
    }
}

ECode AutoTestParseTouchEvent(Void* pThis)
{
    MemoryBuf_<sizeof(TouchData)> mbData;
    STATIC Int32 downX = 0;
    STATIC Int32 downY = 0;
    GrafixObjectStack* stack = (GrafixObjectStack *)pThis;
    IDeviceDriver* touch;
    GrafixObjectEvent event;
    TouchData* data = (TouchData *)mbData.GetPayload();
    ECode ec;

    ec = DzFindService(L"device:touch", (IInterface **)&stack->m_cursorDriver);
    if (GFX_FAILED(ec)) {
        return ec;
    }

    touch = stack->m_cursorDriver;

    while (true) {
        switch (s_uTestType) {
            case TestType_Record :
                ec = touch->Read(0, 1, &mbData, NULL);
                if (GFX_FAILED(ec)) {
                    return ec;
                }

                StylusWriteAt((Byte *)data);
            break;

            case TestType_Replay :
                StylusReadAt((Byte *)data);
            break;

            default :
                ec = touch->Read(0, 1, &mbData, NULL);
                if (GFX_FAILED(ec)) {
                    return ec;
                }
            break;
        }

        if (stack->m_terminate) {
            return NOERROR;
        }

        event.objId = 0;

        // push
        //
        if (3 == data->dir) {
            downX = data->x;
            downY = data->y;

            event.type          = GrafixObjectEventType_StylusHeld;
            event.absoluteX     = data->x;
            event.absoluteY     = data->y;
        }
        // move
        //
        else if (2 == data->dir) {
            Region region = {downX - 3, downY - 3, downX + 3, downY + 3};

            if (!PointInRegion(&region, data->x, data->y)) {
                downX = data->x;
                downY = data->y;

                event.type      = GrafixObjectEventType_StylusMove;
                event.absoluteX = data->x;
                event.absoluteY = data->y;
            }
            else {
                continue;
            }
        }
        // down
        //
        else if (1 == data->dir) {
            downX = data->x;
            downY = data->y;

            event.type          = GrafixObjectEventType_StylusPressed;
            event.modifier     = InputMask_LButton;
            event.absoluteX     = data->x;
            event.absoluteY     = data->y;
        }
        // up
        //
        else if (0 == data->dir) {
            downX = data->x;
            downY = data->y;

            event.type          = GrafixObjectEventType_StylusLifted;
            event.modifier     = InputMask_LButton;
            event.absoluteX     = data->x;
            event.absoluteY     = data->y;
        }
        // push up
        //
        else if (8 == data->dir) {
            downX = data->x;
            downY = data->y;

            event.type          = GrafixObjectEventType_StylusReleased;
            event.absoluteX     = data->x;
            event.absoluteY     = data->y;
        }
#ifdef _DEBUG
        else {
            assert(0 && "impossible");
        }
#endif

        ec = g_lock.Lock();
        if (GFX_FAILED(ec)) {
            return ec;
        }

#ifdef _DEBUG
        ec =
#endif
        stack->PostButtonEvent(event);
        g_lock.Unlock();
#ifdef _DEBUG
        if (GFX_FAILED(ec)) {
            // The window maybe detach from the event buffer, so failed
            //
            continue;
        }
#endif
    }

    return NOERROR;
}

ECode AutoTestParseKeypadEvent(Void* pThis)
{
    MemoryBuf_<sizeof(KPDData)> mbData;
    GrafixObjectStack* stack = (GrafixObjectStack *)pThis;
    IDeviceDriver* keypad;
    GrafixObjectEvent event;
    KPDData* data = (KPDData *)mbData.GetPayload();
    ECode ec;

    ec = DzFindService(L"device:keypad0", (IInterface **)&stack->m_keyDriver);
    if (GFX_FAILED(ec)) {
        return ec;
    }

    keypad = stack->m_keyDriver;

    while (true) {
        switch (s_uTestType) {
            case TestType_Record :
                ec = keypad->Read(0, 1, &mbData, NULL);
                if (GFX_FAILED(ec)) {
                    return ec;
                }

                KeyWriteAt((Byte *)data);
            break;

            case TestType_Replay :
                KeyReadAt((Byte *)data);
            break;

            default :
                ec = keypad->Read(0, 1, &mbData, NULL);
                if (GFX_FAILED(ec)) {
                    return ec;
                }
            break;
        }

        if (stack->m_terminate) {
            return NOERROR;
        }

        event.objId = 0;

        // PressOrRelease
        //
        if (data->status & 0x80000000) {
            if (data->status & 0x00000001) {
                event.type = GrafixObjectEventType_KeyHeld;
            }
            else {
                event.type = GrafixObjectEventType_KeyDown;

                switch (s_uTestType) {
                    case TestType_RecordRandomEvent :
                    case TestType_ReplayRandomEvent :
                    case TestType_RandomReplay :
                        if (data->keycode == VK_VOLUME_DOWN) {
                            if (s_uTestState == TestState_Waiting) {
                                s_pIEvent->Notify(1);
                                s_uTestState = TestState_Running;
                                break;
                            }

                            s_bRandomEvent = !s_bRandomEvent;
                            g_bIsPauseRandomEvent = !g_bIsPauseRandomEvent;

                            if (s_bRandomEvent) s_pIEvent->Notify(1);

                            if (s_fhScript >= 0 && s_nEventIndex > 0) {
                                Write((Byte *)s_pEventBuffer, 4,
                                    s_nEventIndex, s_fhScript);
                                s_nEventIndex = 0;
                            }
                        }
                    break;

                    default : break;
                }
            }
        }
        else {
            if (data->status & 0x00000001) {
                event.type = GrafixObjectEventType_KeyReleased;
            }
            else {
                event.type = GrafixObjectEventType_KeyUp;
            }
        }

        event.keyValue = data->keycode;

        event.modifier = (InputMask)((data->status) & ~0x80000001);

        ec = g_lock.Lock();
        if (GFX_FAILED(ec)) {
            return ec;
        }

#ifdef _DEBUG
        ec =
#endif
        stack->PostKeyEvent(event);
        g_lock.Unlock();
#ifdef _DEBUG
        if (GFX_FAILED(ec)) {
            // The window maybe detach from the event buffer, so failed
            //
            continue;
        }
#endif
    }

    return NOERROR;
}

ECode AutoTestRandEvent(Void* pThis)
{
    s_pStack = (GrafixObjectStack *)pThis;

    RandEvent();

    return NOERROR;
}

#endif // GUI_AUTO_TEST
